Created by miccall (转载请注明出处 miccall.tech)
GUI先继承 ShaderGUI 类 , 然后 重写 OnGUI 方法
public class MyLightingShaderGUI : ShaderGUI
{
publicoverridevoid OnGUI (MaterialEditor editor , MaterialProperty [] properties )
{
}
}
OnGUI有两个参数 ,第一个是 editor , 指代我们当前的编辑器 。
第二个是 properties 数组 ,里面包含了我们在当前材质的shader中,定义的一些公开属性
我们为了以后方便计算 ,把这些设置为全局变量
private Material _target;
private MaterialEditor _editor;
private MaterialProperty[] _properties;
并且在 OnGUI 中为他们赋值
//当前编辑对象的material
_target = editor.target as Material;
_editor = editor ;
_properties = properties ;
然后我们根据shader中的属性,挨个为他们进行属性GUI绘制
首先,在shader中第一个 :
_Tint ("Tint", Color) = (1, 1, 1, 1)
_MainTex ("Albedo", 2D) = "white" {}
我们先来获取他的属性 :
var mainTex = FindProperty("_MainTex") ;
这个函数是我们自己定义的,原来的定义也差不多:
private MaterialProperty FindProperty( string name ) {
return FindProperty ( name , _properties ) ;
}
同理,Tint 也一样
接下来我们自定义个函数
privatestaticreadonly GUIContent StaticLabel = new GUIContent();
privatestatic GUIContent MakeLabel ( MaterialProperty property ,string tooltip = null )
{
StaticLabel.text = property.displayName;
StaticLabel.tooltip = tooltip;
return StaticLabel ;
}
privatestatic GUIContent MakeLabel ( string text , string tooltip = null )
{
StaticLabel.text = text;
StaticLabel.tooltip = tooltip;
return StaticLabel;
}
当然,这是一个重载函数 ,目的是写一个 label 来展示标识 ,这个label的内容,可以直接使用属性本身的显示名字(也就是shader里面定义的显示名字) ,也可以通过重载,来我们自己重写一个名字。
tooltip 是一个提示目的的标语,默认可以为空 。
然后介绍一个方法 :TexturePropertySingleLine 用于显示具有附加内联特性的纹理属性控件的方法。
public Rect TexturePropertySingleLine(GUIContent label, MaterialProperty textureProp);
public Rect TexturePropertySingleLine(GUIContent label, MaterialProperty textureProp, MaterialProperty extraProperty1);
public Rect TexturePropertySingleLine(GUIContent label, MaterialProperty textureProp, MaterialProperty extraProperty1, MaterialProperty extraProperty2);
第一个参数是label ,就是显示名字 ,第二个就是属性 ,第三四个就是附加属性了 ,
我们把texture 和 Tint 结合到一起 :
_editor.TexturePropertySingleLine(MakeLabel(mainTex,"Albedo(RGB)"),mainTex,FindProperty("_Tint"));
这样的话,我们的shader面板就变成:
如果我们想在他的上面加一个标语:
GUILayout.Label("MainMaps",EditorStyles.boldLabel);
接下来,我们继续添加 metallic 贴图 的GUI :
[NoScaleOffset]_MetallicMap("Metallic",2D)="white"{}
[Gamma]_Metallic("Metallic",Range(0,1))=0
var map = FindProperty("_MetallicMap");
EditorGUI.BeginChangeCheck();
_editor.TexturePropertySingleLine(
MakeLabel(map,"Metallic(R)"),map,
map.textureValue ? null : FindProperty("_Metallic")
);
if(EditorGUI.EndChangeCheck()){
SetKeyword("_METALLIC_MAP",map.textureValue);
}
我们可以使用
EditorGUI.BeginChangeCheck
和
EditorGUI.EndChangeCheck
方法检查某些内容是否已更改。
第一种方法定义了我们想要开始跟踪更改的点。
第二种方法标记结束,并返回是否进行了更改。
private void SetKeyword(string keyword,bool state){
if(state){
//将关键字添加到着色器
_target.EnableKeyword(keyword);
}
else{
_target.DisableKeyword(keyword);
}
}
SetKeyword 的目的是为了多分支编译shader版本 ,我们用
#pragmas hader_feature _METALLIC_MAP
来控制 金属度贴图的使用
#if defined (_METALLIC_MAP)
return tex2D( _MetallicMap , i.uv.xy).r;
#else
return _Metallic;
#endif
然后是Smoothness:
_Smoothness("Smoothness",Range(0,1))=0.1
smooness 有三种,
第一个就是固定silder ,
第二种是在 metallic 的alpha 通道
第三种是在 albedo的alpha 通道
我们就要有一个选择器:
#pragma shader_feature _ _SMOOTHNESS_ALBEDO _SMOOTHNESS_METALLIC
float GetSmoothness ( Interpolators i ) {
float smoothness = 1 ;
#if defined( _SMOOTHNESS_ALBEDO )
smoothness = tex2D(_MainTex,i.uv.xy).a;
#elif defined(_SMOOTHNESS_METALLIC)&&defined(_METALLIC_MAP)
smoothness = tex2D(_MetallicMap,i.uv.xy).a;
#endif
return smoothness * _Smoothness ;
}
在GUI中,我们开控制他的选择 :
private enum SmoothnessSource { Uniform , Albedo , Metallic }
private void DoSmoothness () {
// default ?
var source = SmoothnessSource.Uniform ;
if (IsKeywordEnabled("_SMOOTHNESS_ALBEDO")) {
source = SmoothnessSource.Albedo ;
}
else if ( IsKeywordEnabled("_SMOOTHNESS_METALLIC")) {
source = SmoothnessSource.Metallic;
}
var slider = FindProperty("_Smoothness");
EditorGUI.indentLevel += 2;
_editor.ShaderProperty(slider, MakeLabel(slider));
EditorGUI.indentLevel += 1;
EditorGUI.BeginChangeCheck();
source = ( SmoothnessSource ) EditorGUILayout.EnumPopup( MakeLabel("Source"), source );
if ( EditorGUI.EndChangeCheck() ) {
RecordAction("Smoothness Source");
SetKeyword("_SMOOTHNESS_ALBEDO", source == SmoothnessSource.Albedo);
SetKeyword("_SMOOTHNESS_METALLIC", source == SmoothnessSource.Metallic);
}
EditorGUI.indentLevel -= 3;
}
IsKeywordEnabled 是判断当前的 key word 是否是启用状态 :
private bool IsKeywordEnabled ( string keyword ) {
return _target.IsKeywordEnabled( keyword ) ;
}
用户在面板上选取的值,我们通过这个获取
source=(SmoothnessSource)EditorGUILayout.EnumPopup(MakeLabel("Source"),source);
下面就是判断这个值,然后自定义开关一个 keywords 了
再接下来,就是normal map
[NoScaleOffset]_NormalMap("Normals",2D)="bump"{}
_BumpScale("BumpScale",Float)=1
privatevoid DoNormals () {
var map = FindProperty("_NormalMap");
_editor.TexturePropertySingleLine(
MakeLabel(map),map,
map.textureValue?FindProperty("_BumpScale"):null
);
}
自发光贴图:
private void DoEmission(){
var map=FindProperty("_EmissionMap");
EditorGUI.BeginChangeCheck();
_editor.TexturePropertyWithHDRColor(
MakeLabel("Emission(RGB)"),map,FindProperty("_Emission"),
EmissionConfig,false
);
if(EditorGUI.EndChangeCheck()){
SetKeyword("_EMISSION_MAP",map.textureValue);
}
}
float3GetEmission(Interpolatorsi){
#ifdefined(FORWARD_BASE_PASS)
#ifdefined(_EMISSION_MAP)
returntex2D(_EmissionMap,i.uv.xy)*_Emission;
#else
return_Emission;
#endif
#else
return0;
#endif
}